﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
using System.IO;
using System;
using System.Reflection;

public class DefaultEngineResourceManager
{
    private static DefaultEngineResourceManager instance;
    private DefaultEngineResourceManager() { }
    private Dictionary<string, UnityEngine.Object> resources;

    public static DefaultEngineResourceManager Instance
    {
        get
        {
            if (instance == null)
                instance = new DefaultEngineResourceManager();

            return instance;
        }
    }

    public void Init()
    {
        resources = new Dictionary<string, UnityEngine.Object>();

        GameObject cube = GameObject.CreatePrimitive(UnityEngine.PrimitiveType.Cube);
        cube.name = "_UnityCube_";
        cube.SetActive(false);
        resources["_UnityCube_"] = cube.GetComponent<MeshFilter>().sharedMesh;

        GameObject capsule = GameObject.CreatePrimitive(UnityEngine.PrimitiveType.Capsule);
        capsule.name = "_UnityCapsule_";
        capsule.SetActive(false);
        resources["_UnityCapsule_"] = capsule.GetComponent<MeshFilter>().sharedMesh;

        GameObject cylinder = GameObject.CreatePrimitive(UnityEngine.PrimitiveType.Cylinder);
        cylinder.name = "_UnityCylinder_";
        cylinder.SetActive(false);
        resources["_UnityCylinder_"] = cylinder.GetComponent<MeshFilter>().sharedMesh;

        GameObject plane = GameObject.CreatePrimitive(UnityEngine.PrimitiveType.Plane);
        plane.name = "_UnityPlane_";
        plane.SetActive(false);
        resources["_UnityPlane_"] = plane.GetComponent<MeshFilter>().sharedMesh;

        GameObject quad = GameObject.CreatePrimitive(UnityEngine.PrimitiveType.Quad);
        quad.name = "_UnityQuad_";
        quad.SetActive(false);
        resources["_UnityQuad_"] = quad.GetComponent<MeshFilter>().sharedMesh;

        GameObject sphere = GameObject.CreatePrimitive(UnityEngine.PrimitiveType.Sphere);
        sphere.name = "_UnitySphere_";
        sphere.SetActive(false);
        resources["_UnitySphere_"] = sphere.GetComponent<MeshFilter>().sharedMesh;

    }

    public Mesh GetMesh(string name)
    {
        if (resources.ContainsKey(name))
            return (Mesh)resources[name];

        return null;
    }

}

public class CustomLoader : MonoBehaviour
{

    List<DocPrimitive> primitives;
    List<GameObjectValue> gameObjects;
    List<TransformValue> transforms;

    public TextAsset sceneFile;

    readonly string unityDefaultPath = "/unity default resources";

    void Start()
    {
        DefaultEngineResourceManager.Instance.Init();
        // step 1, parse 
        SceneReader.Instance.Init();
        //		string path = Application.dataPath + "/" + "main.unity.txt";
        //		SceneReader.Instance.Parse (path);

        if (sceneFile == null)
            return;

        SceneReader.Instance.ParseString(sceneFile.text);

        // step 2, instantiate
        primitives = SceneReader.Instance.primitiveList;

        // construct all gameobject first, so component has place to attach
        ConstructGameObjects();

        // deal with others except gameobject
        ProcessOthersExceptGameObject();

        // process gameobject hierarchy, link child with parent 
        ProcessGameObjectHierarchy();
    }

    void ConstructGameObjects()
    {
        gameObjects = new List<GameObjectValue>();

        foreach (DocPrimitive dp in primitives)
        {
			if (dp.type == (int)PrimitiveType.GameObject) {
				GameObject go = new GameObject ();

				GameObjectDoc god = (GameObjectDoc)dp;
				go.name = god.goo.name;
				go.isStatic = (god.goo.staticEditorFlags != 0) ? true : false;
				go.SetActive ((god.goo.actived != 0) ? true : false);
				go.layer = god.goo.layer;
				go.tag = god.goo.tag;

				GameObjectValue gov = new GameObjectValue ();
				gov.id = god.id;
				gov.go = go;
				gov.type = god.type;
				gov.originalDp = dp;

				gameObjects.Add (gov);
			} else if (dp.type == (int)PrimitiveType.Prefab) {
				PrefabDoc pd = (PrefabDoc)dp;

				//instantiate this object.Note: the first one must be exist.
				string prefabPath = pd.pl.modification.modifications [0].target ["guid"];
				Debug.Log (prefabPath);

				UnityEngine.Object o = Resources.Load (GetResourcePathSafe (prefabPath));
				GameObject go = Instantiate (o) as GameObject;

				//remove components if have
				for (int i = 0; i < pd.pl.modification.removedComponent.Count; ++i) {
					RemovedComponent rc = pd.pl.modification.removedComponent [i];
					string name = rc.component ["fileID"];
					RemoveComponentOnGameObject (go, name);
				}

				//change modification
				ModifyTransformValue (go, pd.pl.modification.modifications);  //transform is special
				ModifyMaterialValue (go, pd.pl.modification.modifications);   //material is special since we cannot set them one by one

				//transform's position and rotation always exist, and occupy 7 lines, so we here start from line 7
				for (int j = 7; j < pd.pl.modification.modifications.Count; ++j) {
					ModificationMod mm = pd.pl.modification.modifications [j];
					string name = mm.propertyPath;
					ModifyComponentOnGameObject (go, name, mm);
				}

				GameObjectValue gov = new GameObjectValue ();
				gov.id = pd.id;
				gov.go = go;
				gov.type = pd.type;
				gov.originalDp = dp;

				gameObjects.Add (gov);
			}else if (dp.type == (int)PrimitiveType.GameObjectStripped) {
				// GameObject Stripped in Unity3d's scene file is a stub only,
				// so we won't instantiate it really
				GameObjectStrippedDoc gos = (GameObjectStrippedDoc)dp;

				GameObjectValue gov = new GameObjectValue ();
				gov.id = gos.id;
				gov.go = null;     //since it's dummy
				gov.type = gos.type;
				gov.originalDp = dp;

				gameObjects.Add (gov);
			}
        }
    }

    void ProcessOthersExceptGameObject()
    {
        transforms = new List<TransformValue>();

        foreach (DocPrimitive dp in primitives)
        {
			if (dp.type == (int)PrimitiveType.Camera) {
				CameraDoc cd = (CameraDoc)dp;
				GameObject go = FindSkin (cd.co.gameObject.Values.FirstOrDefault ());

				//I don't know, why this has camera component already?
				Camera cam = go.GetComponent<Camera> ();
				//cam.hideFlags = (Hide)cd.co.objectHideFlags;
				cam.enabled = (cd.co.enabled != 0) ? true : false;
				//cam.clearFlags = cd.co.clearFlags;
				cam.backgroundColor = new Color (cd.co.backgroundColor ["r"], cd.co.backgroundColor ["g"], cd.co.backgroundColor ["b"], cd.co.backgroundColor ["a"]);
				cam.nearClipPlane = cd.co.nearClipPlane;
				cam.farClipPlane = cd.co.farClipPlane;
				cam.fieldOfView = cd.co.fieldOfView;

			} else if (dp.type == (int)PrimitiveType.Transform) {
				//Transform is so special(every gameobject has one default and cannot be deleted, we only need it value)
				TransformValue tv = new TransformValue ();

				TransformDoc td = (TransformDoc)dp;
				tv.gameObjectId = td.mbo.gameObject.Values.FirstOrDefault ();
				tv.position = new Vector3 (td.mbo.position ["x"], td.mbo.position ["y"], td.mbo.position ["z"]);
				tv.rotation = new Vector4 (td.mbo.rotation ["x"], td.mbo.rotation ["y"], td.mbo.rotation ["z"], td.mbo.rotation ["w"]);
				tv.scale = new Vector3 (td.mbo.scale ["x"], td.mbo.scale ["y"], td.mbo.scale ["z"]);
				tv.fatherId = td.mbo.father ["fileID"];
				tv.selfId = td.id;

				GameObject go = FindSkin (td.mbo.gameObject.Values.FirstOrDefault ());
				go.transform.localPosition = tv.position;
				go.transform.localRotation = new Quaternion (tv.rotation.x, tv.rotation.y, tv.rotation.z, tv.rotation.w);//Quaternion.Euler (tv.rotation);
				go.transform.localScale = tv.scale;

				tv.transform = go.transform;
				tv.gameobject = go;

				transforms.Add (tv);

				//test
				Transform trans = go.transform;
				foreach (FieldInfo info in typeof(Transform).GetFields()) {
					Debug.LogWarning ("Field name: " + info.Name);
				}

			} else if (dp.type == (int)PrimitiveType.FlaryLayer) {
				BehaviourDoc bd = (BehaviourDoc)dp;
				GameObject go = FindSkin (bd.bo.gameObject.Values.FirstOrDefault ());

				FlareLayer fl = go.AddComponent<FlareLayer> ();
			} else if (dp.type == (int)PrimitiveType.GUILayer) {
				BehaviourDoc bd = (BehaviourDoc)dp;
				GameObject go = FindSkin (bd.bo.gameObject.Values.FirstOrDefault ());

				GUILayer fl = go.AddComponent<GUILayer> ();
			} else if (dp.type == (int)PrimitiveType.MonoBehaviour) {

				MonoBehaviourDoc mbd = (MonoBehaviourDoc)dp;
				GameObject go = FindSkin (mbd.mbo.gameObject.Values.FirstOrDefault ());

				string scriptName = mbd.mbo.script ["guid"];
				if (scriptName != null && scriptName.Contains (".cs")) {
					scriptName = scriptName.Split ('.') [0];
					System.Type scriptType = System.Type.GetType (scriptName);
					Component com = go.AddComponent (scriptType);

					string fields = dp.extension.Trim ();
					if (fields.Length != 0) {
						StringReader reader = new StringReader (fields);

						while (true) {
							string line = reader.ReadLine ();
							if (line == null)
								break;

							string fieldName = line.Split (':') [0].Trim ();
							string fieldValue = line.Split (':') [1];
							if (fieldValue != string.Empty)
								fieldValue = fieldValue.Remove (0, 1); // a space ahead !Note:DONT USE TRIM HERE SINCE VALUE MAYBE IS STRING
							else
								fieldValue = string.Empty;

							AssignFieldValue (com, fieldName, fieldValue, line);
						}
					}
				}
			} else if (dp.type == (int)PrimitiveType.BoxCollider) {
				BoxColliderDoc bcd = (BoxColliderDoc)dp;
				GameObject go = FindSkin (bcd.mfo.gameObject.Values.FirstOrDefault ());

				BoxCollider bc = go.AddComponent<BoxCollider> ();

				bc.isTrigger = bcd.mfo.isTrigger != 0 ? true : false;

				float x = bcd.mfo.center ["x"];
				float y = bcd.mfo.center ["y"];
				float z = bcd.mfo.center ["z"];
				bc.center = new Vector3 (x, y, z);

				x = bcd.mfo.size ["x"];
				y = bcd.mfo.size ["y"];
				z = bcd.mfo.size ["z"];
				bc.size = new Vector3 (x, y, z);

			} else if (dp.type == (int)PrimitiveType.MeshFilter) {
				MeshFilterDoc mfd = (MeshFilterDoc)dp;
				GameObject go = FindSkin (mfd.mfo.gameObject.Values.FirstOrDefault ());

				MeshFilter mf = go.AddComponent<MeshFilter> ();
				//use guid to get resource's name and path
				string path = GetResourcePathSafe (mfd.mfo.mesh ["guid"]);
				Debug.Log ("Resource path: " + path);
				UnityEngine.Object[] res = Resources.LoadAll (path, typeof(Mesh));
				Debug.Log (string.Format ("Load resource now get {0} meshes.", res.Length));

				//get the mesh from resource
				string name = mfd.mfo.mesh ["fileID"];
				Debug.Log ("Mesh name is: " + name);
				if (!name.Contains ("_Unity"))
					for (int i = 0; i < res.Length; ++i) {
						if (name == res [i].name)
							mf.sharedMesh = (Mesh)res [i];
					}
				else {
					mf.sharedMesh = DefaultEngineResourceManager.Instance.GetMesh (name);
				}

			} else if (dp.type == (int)PrimitiveType.MeshRenderer) {
				MeshRendererDoc mrd = (MeshRendererDoc)dp;
				GameObject go = FindSkin (mrd.mro.gameObject.Values.FirstOrDefault ());

				MeshRenderer mr = go.AddComponent<MeshRenderer> ();
				Material[] mats = new Material[mrd.mro.mrm.Count];
				for (int i = 0; i < mats.Length; ++i) {
					string path = GetResourcePathSafe (mrd.mro.mrm [i].material ["guid"]);
					Debug.Log ("Load material, path: " + path);
					Material mat = Resources.Load (path, typeof(Material)) as Material;
					mats [i] = mat;
				}

				// we must assign this after material all ready assigned to array, otherwise unity won't work
				mr.materials = mats;

				mr.receiveShadows = mrd.mro.receiveShadow != 0 ? true : false;
				switch (mrd.mro.castShadow) {
				case 0:
					mr.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
					break;
				case 1:
					mr.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.On;
					break;
				case 2:
					mr.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.TwoSided;
					break;
				case 3:
					mr.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.ShadowsOnly;
					break;
				}
			} else if (dp.type == (int)PrimitiveType.Animation) {
				AnimationDoc ad = (AnimationDoc)dp;
				GameObject go = FindSkin (ad.ao.gameObject.Values.FirstOrDefault ());

				Animation animation = go.AddComponent<Animation> ();
				for (int i = 0; i < ad.ao.animationClips.Count; ++i) {
					if (ad.ao.animationClips [i].clip.ContainsKey ("guid")) {
						string animPath = ad.ao.animationClips [i].clip ["guid"];
						string ext = Path.GetExtension (animPath);
						string name = Path.GetFileName (animPath);
						if (ext == ".anim") {
							animPath = GetResourcePathSafe (animPath);
							AnimationClip ac = Resources.Load (animPath, typeof(AnimationClip)) as AnimationClip;
							animation.AddClip (ac, name);
						} else if (ext.ToLower () == ".fbx") {
							animPath = GetResourcePathSafe (animPath);
							AnimationClip ac = Resources.Load (animPath, typeof(AnimationClip)) as AnimationClip;
							animation.AddClip (ac, name);
						}
					}
				}

				animation.playAutomatically = (ad.ao.playAuto != 0) ? true : false;
			} else if (dp.type == (int)PrimitiveType.Animator) {
				AnimatorDoc ad = (AnimatorDoc)dp;
				GameObject go = FindSkin (ad.ao.gameObject.Values.FirstOrDefault ());

				Animator animator = go.AddComponent<Animator> ();

				animator.applyRootMotion = ad.ao.applyRootMotion != 0 ? true : false;

				//avatar
				if (ad.ao.avatar.ContainsKey ("guid")) {
					string path = ad.ao.avatar ["guid"];
					path = GetResourcePathSafe (path);
					//avatar only exist in fbx file
					UnityEngine.Object[] avatar = Resources.LoadAll<Avatar> (path);
					animator.avatar = (Avatar)(avatar [0]);
				}

				//controller
				if (ad.ao.controller.ContainsKey ("guid")) {
					string path = ad.ao.controller ["guid"];
					path = GetResourcePathSafe (path);
					RuntimeAnimatorController controller = Resources.Load (path) as RuntimeAnimatorController;
					animator.runtimeAnimatorController = controller;
				}
			} else if (dp.type == (int)PrimitiveType.SphereCollider) {
				SphereColliderDoc scd = (SphereColliderDoc)dp;
				GameObject go = FindSkin (scd.sco.gameObject.Values.FirstOrDefault ());

				SphereCollider sc = go.AddComponent<SphereCollider> ();

				sc.isTrigger = scd.sco.isTrigger != 0 ? true : false;
				sc.radius = scd.sco.radius;

				float x = scd.sco.center ["x"];
				float y = scd.sco.center ["y"];
				float z = scd.sco.center ["z"];

				sc.center = new Vector3 (x, y, z);
			} else if (dp.type == (int)PrimitiveType.CapsuleCollider) {
				CapsuleColliderDoc ccd = (CapsuleColliderDoc)dp;
				GameObject go = FindSkin (ccd.cco.gameObject.Values.FirstOrDefault ());

				CapsuleCollider cc = go.AddComponent<CapsuleCollider> ();

				cc.isTrigger = ccd.cco.isTrigger != 0 ? true : false;
				cc.radius = ccd.cco.radius;

				float x = ccd.cco.center ["x"];
				float y = ccd.cco.center ["y"];
				float z = ccd.cco.center ["z"];

				cc.center = new Vector3 (x, y, z);

				cc.height = ccd.cco.height;
				cc.direction = ccd.cco.direction;
			} else if (dp.type == (int)PrimitiveType.MeshCollider) {
				MeshColliderDoc mcd = (MeshColliderDoc)dp;
				GameObject go = FindSkin (mcd.mco.gameObject.Values.FirstOrDefault ());

				MeshCollider mc = go.AddComponent<MeshCollider> ();

				mc.convex = mcd.mco.convex != 0 ? true : false;
				mc.inflateMesh = mcd.mco.inflatMesh != 0 ? true : false;
				mc.skinWidth = mcd.mco.skinWidth;
				mc.isTrigger = mcd.mco.isTrigger != 0 ? true : false;
			}
        }
    }

    void AssignFieldValue(Component com, string fieldName, string fieldValue, string line)
    {
        Type t = com.GetType();

        FieldInfo fi = t.GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);

        if (fi.FieldType == typeof(System.String))
        {
            fi.SetValue(com, fieldValue);
        }
        else if (fi.FieldType == typeof(System.Int32))
        {
            fi.SetValue(com, Int32.Parse(fieldValue));
        }
        else if (fi.FieldType == typeof(System.Byte))
        {
            fi.SetValue(com, byte.Parse(fieldValue));
        }
        else if (fi.FieldType == typeof(System.Int16))
        {
            fi.SetValue(com, short.Parse(fieldValue));
        }
        else if (fi.FieldType == typeof(System.SByte))
        {
            fi.SetValue(com, sbyte.Parse(fieldValue));
        }
        else if (fi.FieldType == typeof(UInt16))
        {
            fi.SetValue(com, ushort.Parse(fieldValue));
        }
        else if (fi.FieldType == typeof(System.UInt32))
        {
            fi.SetValue(com, uint.Parse(fieldValue));
        }
        else if (fi.FieldType == typeof(System.Int64))
        {
            fi.SetValue(com, long.Parse(fieldValue));
        }
        else if (fi.FieldType == typeof(System.UInt64))
        {
            fi.SetValue(com, ulong.Parse(fieldValue));
        }
        else if (fi.FieldType == typeof(System.Single))
        {
            fi.SetValue(com, float.Parse(fieldValue));
        }
        else if (fi.FieldType == typeof(System.Double))
        {
            fi.SetValue(com, double.Parse(fieldValue));
        }
        else if (fi.FieldType == typeof(System.Decimal))
        {
            fi.SetValue(com, decimal.Parse(fieldValue));
        }
        //
        else if (fi.FieldType == typeof(UnityEngine.GameObject))
        {
            //maybe gameobject in hierarchy(Editor), maybe a prefab
            if (line.Contains("guid"))
            {
                //prefab or fbx, load
                string path = line.Split(',')[1].Split(':')[1].Trim();
                path = GetResourcePathSafe(path);
                UnityEngine.Object o = Resources.Load(path);
                fi.SetValue(com, o);
            }
            else
            {
                //gameobject, fileId is not zero
                string strId = line.Split(':')[2].Trim();
                strId = strId.Split('}')[0].Trim();
                uint id = uint.Parse(strId);

                if (id != 0)
                {
                    GameObject go = FindSkin(id);
                    fi.SetValue(com, go);
                }
            }
        }
        else if (fi.FieldType == typeof(UnityEngine.Material))
        {
            if (line.Contains("guid"))
            {
                string path = line.Split(',')[1].Split(':')[1].Trim();
                path = GetResourcePathSafe(path);
                Material mat = Resources.Load(path, typeof(Material)) as Material;
                fi.SetValue(com, mat);
            }
        }
        else if (fi.FieldType == typeof(UnityEngine.Texture))
        {
            if (line.Contains("guid"))
            {
                string path = line.Split(',')[1].Split(':')[1].Trim();
                path = GetResourcePathSafe(path);
                Texture tex = Resources.Load(path, typeof(Texture)) as Texture;
                fi.SetValue(com, tex);
            }
        }
        else
        {
            Debug.LogWarning(string.Format("{0} not supported in this version.", fi.FieldType));
        }
    }

    void ModifyTransformValue(GameObject go, List<ModificationMod> mods)
    {
        Debug.Assert(mods.Count >= 7);

        // layzy here
        float x, y, z, w;
        x = float.Parse(mods[0].value);
        y = float.Parse(mods[1].value);
        z = float.Parse(mods[2].value);

        go.transform.localPosition = new Vector3(x, y, z);

        x = float.Parse(mods[3].value);
        y = float.Parse(mods[4].value);
        z = float.Parse(mods[5].value);
        w = float.Parse(mods[6].value);

        go.transform.localRotation = new Quaternion(x, y, z, w);
    }

    void ProcessGameObjectHierarchy()
    {
        foreach (TransformValue tv in transforms)
        {
            Transform father = FindFather(tv.fatherId);

            tv.transform.parent = father;

            tv.transform.localPosition = tv.position;
            tv.transform.localRotation = new Quaternion(tv.rotation.x, tv.rotation.y, tv.rotation.z, tv.rotation.w);//Quaternion.Euler (tv.rotation);
            tv.transform.localScale = tv.scale;
        }
    }

    void RemoveComponentOnGameObject(GameObject go, string name)
    {
        if (name == "MeshFilter")
        {
            Destroy(go.GetComponent<MeshFilter>());
        }
        else if (name == "BoxCollider")
        {
            Destroy(go.GetComponent<BoxCollider>());
        }
        else if (name == "MeshRenderer" || name == "SkinMeshRenderer")
        {
            Destroy(go.GetComponent<Renderer>());
        }
    }

    void ModifyMaterialValue(GameObject go, List<ModificationMod> mods)
    {
        List<Material> matContainer = new List<Material>();

        for (int i = 0; i < mods.Count; ++i)
        {
            if (mods[i].propertyPath.Contains("m_Materials.Array.data["))
            {
                string path = GetResourcePathSafe(mods[i].objectRef["guid"]);
                Material mat = Resources.Load(path, typeof(Material)) as Material;
                matContainer.Add(mat);
            }
        }

        if (matContainer.Count == 0) return;

        go.GetComponent<Renderer>().materials = matContainer.ToArray();
    }

    void ModifyComponentOnGameObject(GameObject go, string propertyPath, ModificationMod mm)
    {
        // tranform, material is special, so dealed in other function
        if (propertyPath == "m_Name")
        {
            go.name = mm.value;
        }
        else if (propertyPath == "m_Mesh")
        {
            MeshFilter mf = go.GetComponent<MeshFilter>();

            string guid = mm.objectRef["guid"];
            string fileId = mm.objectRef["fileID"];

            if (guid == unityDefaultPath)
            {
                Mesh m = DefaultEngineResourceManager.Instance.GetMesh(fileId);
                mf.mesh = m;
            }
            else
            {
                string path = GetResourcePathSafe(guid);
                UnityEngine.Object[] res = Resources.LoadAll(path, typeof(Mesh));
                for (int i = 0; i < res.Length; ++i)
                {
                    if (res[i].name == fileId)
                    {
                        mf.mesh = (Mesh)res[i];
                    }
                }
            }
        }
        else
        {
            Debug.Log(string.Format("propertyPath {0} now I don't know how to deal with.", propertyPath));
        }
    }

    //skin from Chinese "if there is no skin, where can the fur attach?" 
    GameObject FindSkin(uint id)
    {
        for (int i = 0; i < gameObjects.Count; ++i)
        {
            if (gameObjects[i].id == id)
            {
				if (gameObjects [i].type == (int)PrimitiveType.GameObject)
					return gameObjects [i].go;
				else if (gameObjects [i].type == (int)PrimitiveType.GameObjectStripped) {
					GameObjectStrippedDoc gos = (GameObjectStrippedDoc)gameObjects [i].originalDp;
					id = gos.gos.prefabInternal["fileID"];
					return FindSkinOnGameObjectNotStripped (id);
				}
            }
        }

        return null;
    }

	GameObject FindSkinOnGameObjectNotStripped(uint id)
	{
		for (int i = 0; i < gameObjects.Count; ++i)
		{
			if (gameObjects[i].id == id)
			{
				if (gameObjects [i].type == (int)PrimitiveType.GameObject ||
					gameObjects [i].type == (int)PrimitiveType.Prefab){
					return gameObjects [i].go;
				}
			}
		}

		return null;
	}

    Transform FindFather(uint self)
    {
        if (self == 0)
            return null;

        foreach (TransformValue tv in transforms)
        {
            if (tv.selfId == self)
                return tv.transform;
        }

        return null;
    }

    string GetResourcePathSafe(string origin)
    {
        if (origin == unityDefaultPath)
            return origin;

        string tag = "Resources/";

        if (origin.Length <= tag.Length)
        {
            Debug.LogError(string.Format("A path: {0} given, but it's not valid as a Path for Resources.Load().", origin));
            return null;
        }

        string path = origin.Substring(0, tag.Length);
        if (path != tag)
        {
            Debug.LogError(string.Format("A path: {0} given, but it's not valid as a Path for Resources.Load(), since it's not start with 'Resources/'", origin));
            return null;
        }

        path = origin.Remove(0, tag.Length).Split('.')[0];
        return path;
    }

    void OnGUI()
    {
        GameObject[] gos = GameObject.FindObjectsOfType(typeof(GameObject)) as GameObject[];
        GUI.Label(new Rect(100, 100, 300, 200), string.Format("Find {0} gameobjets", gos.Length));
    }

}
